fn slice() {
    let s = String::from("hello world");
    let x = &s[0..5];   // same as &s[0..5]
    let y = &s[6..11];  // same as &s[6..11]
    let z = &s[..];     // same as &s[0..11]

    println!("\n------------- Test Slice --------------");
    println!("x: {}, y: {}, z: {}", x, y, z);
}

fn say_hello(v: &str) {
    println!("v: {}", v);
}

fn string_remove() {
    let s1 = String::from("测试remove方法");
    println!("s1: {}, 长度 {}, 占 {} 字节", s1, s1.len(), std::mem::size_of_val(&s1));

    let mut s2 = s1.clone();
    s2.pop();
    println!("pop: {}, 长度 {}, 占 {} 字节", s2, s2.len(), std::mem::size_of_val(&s2));

    let mut s3 = s1.clone();
    s3.remove(0);
    println!("remove: {}, 长度 {}, 占 {} 字节", s3, s3.len(), std::mem::size_of_val(&s3));

    let mut s4 = s1.clone();
    s4.truncate(6);
    println!("truncate: {}, 长度 {}, 占 {} 字节", s4, s4.len(), std::mem::size_of_val(&s4));

    let mut s5 = s1.clone();
    s5.clear();
    println!("clear: {}, 长度 {}, 占 {} 字节", s5, s5.len(), std::mem::size_of_val(&s5));
}

fn concatenate() {
    let s1 = String::from("hello ");
    let s2 = String::from("rust");
    let s3 = s1 + &s2;
    let mut s4 = s3 + "!";

    s4 += "!!!";
    println!("concatenate: {}", s4);
}

fn format() {
    let s1 = String::from("hello");
    let s2 = String::from("world");
    let s3 = format!("{} {}!", s1, s2);
    println!("format: {}", s3);
}

fn escape() {
    println!("\n------------ Test Escape --------------");

    // 通过 \ + 字符的十六进制表示，转义输出一个字符
    println!("1: {}", "I'm writing \x52\x75\x73\x74!");

    // \u 可以输出一个 unicode 字符
    println!("2: {}", "\u{211D}");
    println!("3: {}", "\"DOUBLE-STRUCK CAPITAL R\"");

    // 换行了也会保持之前的字符串格式
    // 使用\忽略换行符
    println!("4: {}", "String literals
                        can span multiple lines.
                        The linebreak and indentation here ->\
                        <- can be escaped too!");
}

fn traverse_utf8_string() {
    let mut c_index = 0;
    let mut b_index = 0;
    let s = "hello, 我是kangkang!";

    println!("\n--------- Test UTF-8 String -----------");
    println!("s.chars.count: {}", s.chars().count());
    for c in s.chars() {
        println!("{}: {}", c_index, c);
        c_index += 1;
    }

    println!("s.bytes: {}", s.bytes().count());
    for b in s.bytes() {
        println!("{}: {}", b_index, b);
        b_index += 1;
    }
}

fn string_operations() {
    // String -> &str
    let mut s = String::from("hello world");

    println!("\n------------ Test String --------------");
    say_hello(&s);
    say_hello(&s[..]);
    say_hello(s.as_str());

    s.push_str(" how are you");
    println!("push_str: {}", s);
    s.push('?');
    println!("push: {}", s);
    s.insert(11, ',');
    println!("insert: {}", s);
    s.insert_str(12, " >_<");
    println!("insert_str: {}", s);

    let new = s.replace("world", "kangkang");
    println!("replace: {}", new);

    let x = String::from("hello hello hello");
    let new = x.replacen("hello", "hi", 2);
    println!("replacen: {}", new);

    let mut y = String::from("hello hello hello");
    y.replace_range(6..11, "hi");
    println!("replace_range: {}", y);

    let mut z = String::from("hello hello hello");
    z.pop();
    println!("pop: {}", z);

    string_remove();
    concatenate();
    format();
}

fn test_string() {
    slice();
    string_operations();
    escape();
    traverse_utf8_string();
}

fn return_tuple(s: String) -> (String, usize, usize) {
    let cc = s.chars().count();
    let sc = s.bytes().count();
    (s, cc, sc)
}

fn test_tuple() {
    let tup = (500, 6.4, "hello");
    let (x, y, z) = tup;

    println!("\n------------ Test Tuple ---------------");
    println!("x: {}, y: {}, z: {}", x, y, z);
    println!("tup.0: {}, tup.1: {}, tup.2: {}", tup.0, tup.1, tup.2);

    let (s, cc, sc) = return_tuple(String::from("我喜欢Rust"));
    println!("s: {}, cc: {}, sc: {}", s, cc, sc);
}

#[derive(Clone, Debug)]
struct User {
    active: bool,
    username: String,
    email: String,
    company: String,
    sign_in_count: u64,
}

fn fn_struct() {
    println!("\n------------ Test Struct ---------------");

    let user1 = User {
        email: String::from("user1@example.com"),
        username: String::from("user1_123"),
        company: String::from("有限公司"),
        active: true,
        sign_in_count: 1,
    };

    println!("user1: {:#?}", user1);

    let user2 = User {
        email: String::from("user2@example.com"),
        username: String::from("user2_123"),
        ..user1.clone()
    };

    println!("user2: {:#?}", user2);
}

#[derive(Debug)]
struct Color(i32, i32, i32);
#[derive(Debug)]
struct Point(i32, i32, i32);
fn tuple_struct() {
    let black = Color(0, 0, 0);
    let origin = Point(0, 0, 0);

    println!("\n--------- Test Tuple Struct ------------");
    println!("black: {:?}", black);
    println!("origin: {:?}", origin);
}

struct Person {
    name: String,
    age: u8,
}

impl Person {
    fn new(name: &str) -> Person {
        Person { name: String::from(name), age: 0 }
    }

    fn set_age(&mut self, age: u8) {
        self.age = age;
    }

    fn talk(&self) {
        println!("Hello, I'm {}, {} years old", self.name, self.age);
    }
}

fn unit_struct() {
    let mut kangkang = Person::new("kangkang");
    kangkang.set_age(18);
    kangkang.talk();
}

fn test_struct() {
    fn_struct();
    tuple_struct();
    unit_struct();
}

#[derive(Debug)]
enum PokerSuit {
    Clubs(u8),
    Diamonds(u8),
    Hearts(u8),
    Spades(u8),
}

fn test_enum() {
    let c1 = PokerSuit::Clubs(1);
    let c2 = PokerSuit::Clubs(2);
    let d1 = PokerSuit::Diamonds(1);
    let d2 = PokerSuit::Diamonds(2);
    let s1 = PokerSuit::Spades(1);
    let s2 = PokerSuit::Spades(2);
    let h1 = PokerSuit::Hearts(1);
    let h2 = PokerSuit::Hearts(2);

    println!("\n------------- Test Enum ----------------");
    println!("c1: {:?}, c2: {:?}", c1, c2);
    println!("d1: {:?}, d2: {:?}", d1, d2);
    println!("s1: {:?}, s2: {:?}", s1, s2);
    println!("h1: {:?}, h2: {:?}", h1, h2);
}

fn tets_array() {
    let a = [1, 2, 3, 4, 5];
    let b: [i32; 5] = [3; 5];
    let c = [2; 5]; // [2, 2, 2, 2, 2]

    println!("\n------------- Test Array ----------------");
    println!("a: {:?}", a);
    println!("b: {:?}", b);
    println!("c: {:?}", c);

    let a_strings = ["hello"; 2];
    println!("a_strings: {:?}", a_strings);

    let b_strings: [String; 8] = std::array::from_fn(|_i| String::from("hello"));
    println!("b_strings: {:?}", b_strings);

    let a_arrays: [i32; 5] = [1, 2, 3, 4, 5];
    let a_slice: &[i32] = &a_arrays[1..3];
    println!("a_slice: {:?}", a_slice);
}

fn main() {
    test_string();
    test_tuple();
    test_struct();
    test_enum();
    tets_array();
}
